package com.hp.test.java8.lambda.stream;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * We can create stream in the following ways.
 * 1,Create Streams from values
 * 2,Create Streams from Empty streams
 * 3,Create Streams from functions
 * 4,Create Streams from arrays
 * 5,Create Streams from collections
 * 6,Create Streams from files
 * 7,Create Streams from other sources
 */
public class StreamCreateExam {

    /**
     * We can use of() from Stream interface to create a sequential Stream from a single value and multiple values .
     * <T> Stream<T> of(T  t)
     * <T> Stream<T> of(T...values)
     */
    public static void ofExam() {
        // 1,creates a stream from a single value
        Stream<String> stream = Stream.of("Hello world");
        stream.forEach(System.out::println);

        // 2,create a stream from varied length parameters
        Stream<String> streams = Stream.of("XML", "Java", "CSS", "SQL");
        streams.forEach(System.out::println);

        // 3,create a stream from an array of objects
        String[] names = {"XML", "Java", "SQL", "CSS"};
        Stream<String> streamArray = Stream.of(names);
        streamArray.forEach(System.out::println);
    }

    public static void buildExam() {
        // 4,create a stream builder
        Stream<String> stream = Stream.<String>builder().add("XML").add("Java").add("CSS").add("SQL").build();
        stream.forEach(System.out::println);
    }

    public static void emptyExam() {
        // 5,use empty() static method from Stream interface to create an empty sequential stream.
        Stream<String> stream = Stream.empty();
        stream.forEach(System.out::println);
    }

    /**
     * use the following two methods from IntStream interfaces to create IntStream from a range of int values.
     * IntStream range(int start, int end)
     * IntStream rangeClosed(int start, int end).
     */
    public static void rangeExam() {
        // 6,the specified end is exclusive in the range() method
        IntStream oneToFive1 = IntStream.range(1, 6);
        oneToFive1.forEach(System.out::println);

        // 7,the specified end is inclusive in the rangeClosed() method
        IntStream oneToFive2 = IntStream.rangeClosed(1, 5);
        oneToFive2.forEach(System.out::println);
    }

    /**
     * <T> Stream<T> iterate(T  seed, UnaryOperator<T>  f)
     * iterate() method creates a sequential ordered stream.
     * IntStream, LongStream, and DoubleStream contain iterate() methods that
     * take parameters specific to their primitive types and generate values.
     * IntStream iterate(int seed,  IntUnaryOperator f)
     * A seed is the first element of the stream.
     * The second element is generated by applying the function to the first element.
     * The third element is generated by applying the function on the second element.
     * Therefore the elements are: seed, f(seed), f(f(seed)), f(f(f(seed)))...
     */
    public static void iterateExam() {
        // 8,iterate() method creates a sequential ordered stream
        Stream<Long> tenNaturalNumbers = Stream.iterate(1L, n -> n + 1).limit(10);
        tenNaturalNumbers.forEach(System.out::println);
    }

    /**
     * <T> Stream<T> generate(Supplier<T> s)
     * generate() method creates a sequential unordered stream.
     * To generate a stream in which the next element is generated based on the previous one,
     * you will need to use a Supplier that stores the last generated element.
     */
    public static void generateExam() {
        // 9,generate(Supplier<T> s) uses Supplier to generate an infinite sequential unordered stream.
        Stream.generate(Math::random).limit(5).forEach(System.out::println);
    }

    /**
     * java.util.Random class provides ints(), longs(), and doubles() return infinite IntStream,
     * LongStream, and DoubleStream, respectively.
     */
    public static void randomExam() {
        // 10,ints() return infinite IntStream
        new Random().ints().limit(5).forEach(System.out::println);
    }

    public static void collectionExam() {
        // 11,The Collection interface contains the stream() and parallelStream() methods
        // that create sequential and parallel streams from a Collection, respectively
        Set<String> names = new HashSet<>();
        names.add("XML");
        names.add("Java");

        Stream<String> sequentialStream = names.stream();
        sequentialStream.forEach(System.out::println);

        Stream<String> parallelStream = names.parallelStream();
        parallelStream.forEach(System.out::println);
    }

    /**
     * chars() from the CharSequence interface returns an IntStream
     * whose elements are int values representing the characters.
     */
    public static void stringExam() {
        // 12,use chars() method on a String, a StringBuilder, and a StringBuffer
        String str = "5 123,123,qwe,1,123, 25";
        str.chars()
           .filter(n -> !Character.isDigit((char) n) && !Character.isWhitespace((char) n))
           .forEach(n -> System.out.print((char) n));// 结果：,,qwe,,,
    }

    /**
     * splitAsStream(CharSequence input) method from the java.util.regex.
     * Pattern class returns a stream of String whose elements match the pattern.
     */
    public static void regexExam() {
        // 13,streams from regex
        String str = "XML,CSS,HTML";
        Pattern.compile(",").splitAsStream(str).forEach(System.out::println);
    }

    /**
     * java.io and java.nio.file packages from Java 8 has added
     * many methods to support I/O operations using streams.
     * We can read text from a file as a stream of strings.
     * Each element in the stream represents one line of text.
     * We can also use a stream to read JarEntry from a JarFile
     * and we can read entries in a directory as a stream of Path
     * Calling the close() method on the stream will close the underlying file.
     * Alternatively, we can create the stream in a try-with-resources statement
     * so the underlying file is closed automatically.
     * BaseStream extends AutoCloseable
     */
    public static void fileExam() {
        // 14,Java Stream From Files
        Path path = Paths.get("C:/workspace/codes/exam/src/lambda/StreamCreateExam.java");
        try (Stream<String> lines = Files.lines(path)) {
            lines.forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        } // auto close
    }
}
